import axios, { AxiosRequestConfig } from 'axios'
import { PluginObject } from 'vue'
import md5 from 'md5'
import { AppInfo, loading } from '@/lib/appMethods'
import { SET_USER_INFO, SET_GLOBAL_DIALOG } from '@/store/mutations'
import { Toast } from 'vant'
import appStore from '@/store/store'
import { APIS_CONFIG } from '@/lib/apis'
import { Store } from 'vuex'

const HttpPlugin:PluginObject<AxiosRequestConfig> = {
  install (Vue) {
    // token: this.$store.state.userInfo.token,
    Vue.prototype.$axios = function (
      data: AxiosRequestConfig,
      dealError: any = 0,
      reLoginCallBack: any) {
      return request.call(this, data, this.$store, dealError, reLoginCallBack).then((res: any) => {
        return res
      }, (error: any) => {
        console.log('http error', error)
        throw error
      })
    }
  },
}

const fixedString = 'abfdb3f36565ecb7d944303845392592'
function sign (timeStamp: number, url: string) {
  const urlArr = url.split('/')
  const methodName = urlArr[urlArr.length - 1].toLocaleLowerCase()
  const signName = [fixedString, timeStamp, methodName].sort().join('')
  return md5(signName)
}

/**
 * 判断是否显示loading
 * @param data 接口发送数据
 */
function whetherShowLoading (url: string) {
  return window.isPageLoading && APIS_CONFIG[url] &&
  APIS_CONFIG[url].showLoading
}

let tokenOutdateCount = 0
/**
 * 接口请求
 * @param {*} [{ data = {}, ...othOptions }={} as AxiosRequestConfig]
 * @param {number} [dealError=0] 0:不处理错误 2处理错误但不跳转登陆
 * @param {*} [store={} as any] vuex store
 * @returns
 */
export function request (
  { data = {}, ...othOptions } = {} as AxiosRequestConfig,
  store = appStore as any,
  dealError = 0,
  reLoginCallBack?: any
) {
  // console.log(othOptions.url, data)
  const showLoading = whetherShowLoading(othOptions.url!)
  showLoading && loading.show('', `api#${othOptions.url}`)
  const now = Date.now()
  const dataName = othOptions.method && othOptions.method.toLocaleLowerCase() === 'get'
    ? 'params' : 'data'
  const { state: { instInfo = {}, userInfo = {} } = {} } = store
  const instId = instInfo ? instInfo.TrainingInstitutionId : ''
  return axios({
    baseURL: 'http://81.70.41.226:8003/api/', // 打包的时候记得放开注释
    // baseURL: '/api/',
    withCredentials: true,
    method: 'post',
    [dataName]: {
      // TrainingInstitutionId: 173,
      // SchoolId: 173,
      // Token: userInfo ? userInfo.UserId : undefined,
      ...data,
    },
    headers: {
      SignsValue: sign(now, othOptions.url!),
      TimeStamp: now,
      Authorization: userInfo ? userInfo.Token : '',
    },
    ...othOptions,
  }).then(({ data }) => {
    showLoading && loading.hide(`api#${othOptions.url}`)
    if (data.code === HTTP_CODES.tokenExpired) {
      tokenOutdateCount++
      store.dispatch('LOGOUT')
    }
    if (data.code === 200) {
      return data.data
    } else {
      if (dealError === 0 && !(AppInfo.isApp && data.code === HTTP_CODES.tokenExpired)) {
        const errMsg = data.message
        errMsg && Toast(errMsg)
      }
      if (data.code === HTTP_CODES.tokenExpired) {
        if (AppInfo.isApp) {
          if (tokenOutdateCount === 1) {
            AppInfo.callMethod('reLogin', '', true).then((userData) => {
              tokenOutdateCount = 0
              console.log('登陆失效，重新登陆', data.url, userData)
              store.commit(SET_USER_INFO, userData)
              reLoginCallBack && reLoginCallBack()
            })
          }
        } else {
          if (location.pathname !== '/') {
            store.commit(SET_GLOBAL_DIALOG, 'LoginForm')
          }
          // Message.error('您的账号登录已失效！')
          // this.$router.push('/login')
          // @ts-ignore
          // const router = this.$router
          // if (router) {
          //   router.push('/login')
          // } else {
          //   location.href = '/login'
          // }
        }
        // eslint-disable-next-line prefer-promise-reject-errors
        // return Promise.reject(data)
      }
      throw data
    }
  }, (err) => {
    showLoading && loading.hide(`api.err#${othOptions.url}`)
    const response = err.response || {}
    // eslint-disable-next-line no-throw-literal
    throw {
      message: err.message === 'Network Error' ? '网络中断，请检查您的网络' : err.message,
      status: response.status,
      statusText: response.statusText,
    }
  })
}

export function syncRequest ({ url, data, method = 'get' }: ISyncRequestOptions) {
  const now = Date.now()
  const xhr = new XMLHttpRequest()
  let apiUrl = '/api/' + url

  const { state: { instInfo = {}, userInfo = {} } = {} } = appStore as any
  // const instId = instInfo ? instInfo.TrainingInstitutionId : ''
  const initData: any = {
    TrainingInstitutionId: 173,
    SchoolId: 173,
  }
  if (userInfo) {
    initData.Token = userInfo.Token
  }
  const cData = Object.keys(data).reduce((prev, k) => {
    if (data[k] !== undefined) {
      return { ...prev, [k]: data[k] }
    }
    return prev
  }, initData)
  if (method === 'get') {
    const purl = Object.keys(cData).map(k => `${k}=${cData[k]}`).join('&')
    apiUrl += `?${purl}`
  }
  xhr.open(method, apiUrl, false)
  xhr.setRequestHeader('content-type', 'application/json')
  xhr.setRequestHeader('SignsValue', sign(now, url))
  xhr.setRequestHeader('TimeStamp', `${now}`)
  xhr.setRequestHeader('Authorization', userInfo ? userInfo.Token : '')
  xhr.send(JSON.stringify(cData))
}

export const HTTP_CODES = {
  'tokenExpired': 401,
}

export default HttpPlugin

interface ISyncRequestOptions {
  method?: string
  url: string
  data: any
}

declare module 'vue/types/vue' {
  interface Vue {
    /**
     *
     *
     * @param {AxiosRequestConfig} config
     * @param {number} [dealError] 0:自动Toast显示错误 1：错误时不自动报错，返回错误信息 2：手动处理用户信息登陆失效
     * @returns {Promise<any>}
     */
    $axios(data: AxiosRequestConfig, dealError?: number, reLoginCallBack?: any): Promise<any>

    syncRequest(options: ISyncRequestOptions): void
  }
}
